package com.wc.alorithm_blue_bridge_history.littlewhite.Q231223.Q9991;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;

/**
 * @Author congege
 * @Description
 * @Date Created in 2023/12/23-20:14
 */
public class Main {
    static int maxN = (int) 1e5 + 7;
    static long[][] val = new long[maxN << 2][4];
    static long[][] array = new long[maxN][4];
    static long[][] split = new long[maxN << 2][4];
    static int n, m;
    static int mod = 998244353;
    static FastReader in = new FastReader();
    static PrintWriter out = new PrintWriter(System.out);

    public static void main(String[] args) {
        for (int i = 1; i < maxN; i++) {
            Arrays.fill(split[i], 1);
        }
        n = in.nextInt();
        m = in.nextInt();

        for (int i = 1; i <= n; i++) {
            array[i][in.nextInt()]++;
        }
        build(1, n, 1);
        while (m-- > 0) {
            int type, l, r, a, b;
            l = in.nextInt();
            r = in.nextInt();
            type = in.nextInt();
            a = in.nextInt();
            if (type == 1) {
                b = in.nextInt();
                change(1, n, 1, l, r, a, b);
            } else if (type == 2) {
                b = in.nextInt();
                paint(1, n, 1, l, r, a, b);
            } else {
                split(1, n, 1, l, r, a);
            }

            printAns();
        }
        out.flush();
    }

    public static int[][] getE() {
        int[][] E = new int[4][4];
        for (int i = 1; i <= 3; i++) {
            E[i][i] = 1;
        }
        return E;
    }

    public static void printAns() {
        StringBuffer ans = new StringBuffer();
        ans.append(val[1][1]);
        for (int i = 2; i <= 3; i++) {
            ans.append(' ');
            ans.append(val[1][i]);
        }
        out.println(ans);
    }

    public static void build(int l, int r, int t) {
        if (l == r) {
            for (int i = 1; i <= 3; i++) {
                val[t][i] = array[l][i] % mod;
            }
            return;
        }

        int mid = (l + r) >> 1;
        build(l, mid, t << 1);
        build(mid + 1, r, t << 1 | 1);
        pushUp(t);
    }

    public static void pushUp(int t) {
        for (int i = 1; i <= 3; i++) {
            val[t][i] = (val[t << 1][i] + val[t << 1 | 1][i]) % mod;
        }
    }

    public static void change(int l, int r, int t, int ql, int qr, int a, int b) {
        if (l == ql && r == qr) {
            long tmp = val[t][b];
            val[t][b] = val[t][a];
            val[t][a] = tmp;
            if (l != r) {
                int mid = (l + r) >> 1;
                change(l, mid, t << 1, l, mid, a, b);
                change(mid + 1, r, t << 1 | 1, mid + 1, r, a, b);
            }
            return;
        }
        pushDown(t);
        int mid = (l + r) >> 1;
        if (mid >= qr) {
            change(l, mid, t << 1, ql, qr, a, b);
        } else if (mid < ql) {
            change(mid + 1, r, t << 1 | 1, ql, qr, a, b);
        } else {
            change(l, mid, t << 1, ql, mid, a, b);
            change(mid + 1, r, t << 1 | 1, mid + 1, qr, a, b);
        }
        pushUp(t);
    }

    public static void paint(int l, int r, int t, int ql, int qr, int a, int b) {
        if (l == ql && r == qr) {
            val[t][b] = (val[t][b] + val[t][a]) % mod;
            val[t][a] = 0;
            if (l != r) {
                int mid = (l + r) >> 1;
                paint(l, mid, t << 1, l, mid, a, b);
                paint(mid + 1, r, t << 1 | 1, mid + 1, r, a, b);
            }
            return;
        }
        pushDown(t);
        int mid = (l + r) >> 1;
        if (mid >= qr) {
            paint(l, mid, t << 1, ql, qr, a, b);
        } else if (mid < ql) {
            paint(mid + 1, r, t << 1 | 1, ql, qr, a, b);
        } else {
            paint(l, mid, t << 1, ql, mid, a, b);
            paint(mid + 1, r, t << 1 | 1, mid + 1, qr, a, b);
        }
        pushUp(t);
    }

    public static void split(int l, int r, int t, int ql, int qr, int a) {
        if (l == ql && r == qr) {
            val[t][a] = val[t][a] * 2 % mod;
            split[t][a] = (split[t][a] * 2) % mod;
//            if (l != r) {
//                int mid = (l + r) >> 1;
//                split(l, mid, t << 1, l, mid, a);
//                split(mid + 1, r, t << 1 | 1, mid + 1, r, a);
//            }
            return;
        }
        pushDown(t);
        int mid = (l + r) >> 1;
        if (mid >= qr) {
            split(l, mid, t << 1, ql, qr, a);
        } else if (mid < ql) {
            split(mid + 1, r, t << 1 | 1, ql, qr, a);
        } else {
            split(l, mid, t << 1, ql, mid, a);
            split(mid + 1, r, t << 1 | 1, mid + 1, qr, a);
        }
        pushUp(t);
    }

    public static void pushDown(int t) {
        for (int i = 1; i <= 3; i++) {
            if (split[t][i] != 1) {
                val[t << 1][i] = val[t << 1][i] * split[t][i] % mod;
                val[t << 1 | 1][i] = val[t << 1 | 1][i] * split[t << 1 | 1][i] % mod;
                split[t << 1][i] = 1;
                split[t << 1 | 1][i] = 1;
                split[t][i] = 1;
            }
        }
    }
}

class FastReader {
    StringTokenizer st;
    BufferedReader br;

    FastReader() {
        br = new BufferedReader(new InputStreamReader(System.in));
    }

    String next() {
        while (st == null || !st.hasMoreElements()) {
            try {
                st = new StringTokenizer(br.readLine());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return st.nextToken();
    }

    long nextLong() {
        return Long.parseLong(next());
    }

    int nextInt() {
        return Integer.parseInt(next());
    }
}
